import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:tappay_charge/models/tappay_card_type.dart';
import 'package:tappay_charge/models/tappay_prime.dart';
import 'package:tappay_charge/models/tappay_sdk_common_result.dart';
import 'package:tappay_charge/models/tappay_cart_item.dart';

import 'tappay_charge_platform_interface.dart';

/// An implementation of [TappayChargePlatform] that uses method channels.
class MethodChannelTappayCharge extends TappayChargePlatform {
  /// The method channel used to interact with the native platform.
  @visibleForTesting
  final methodChannel = const MethodChannel('tappay_charge');

  @override
  Future<String?> getPlatformVersion() async {
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }

  @override
  Future<TappaySdkCommonResult> initTappay({
    required int appId,
    required String appKey,
    required bool isSandBox
  }) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'initTappay',
      <String, dynamic>{
        'appId': appId,
        'appKey': appKey,
        'isSandBox': isSandBox,
      },
    );

    if (result != null) {
      return TappaySdkCommonResult.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappaySdkCommonResult(
        success: false,
        message: 'Encountered an unknown error when init tappay',
      );
    }
  }

  @override
  Future<bool> validateCard({
    required String cardNumber,
    required String dueMonth,
    required String dueYear,
    required String ccv,
  }) async {
    final result = await methodChannel.invokeMethod<bool>('validateCard', <String, dynamic>{
      'cardNumber': cardNumber,
      'dueMonth': dueMonth,
      'dueYear': dueYear,
      'ccv': ccv,
    });

    return result ?? false;
  }

  @override
  Future<TappayPrime> getCardPrime({
    required String cardNumber,
    required String dueMonth,
    required String dueYear,
    required String ccv,
  }) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'getCardPrime',
      <String, dynamic>{
        'cardNumber': cardNumber,
        'dueMonth': dueMonth,
        'dueYear': dueYear,
        'ccv': ccv,
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when get card prime',
      );
    }
  }

  @override
  Future<TappaySdkCommonResult> initApplePay({
    required String merchantId,
    required String merchantName,
    String? currencyCode,
    String? countryCode,
    List<TappayCardType>? supportedCardTypes,
  }) async {
    if (!Platform.isIOS) {
      return TappaySdkCommonResult(
        success: false,
        message: "Apple pay is only available on iOS",
      );
    }

    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'initApplePay',
      <String, dynamic>{
        'merchantId': merchantId,
        'merchantName': merchantName,
        'currencyCode': currencyCode,
        'countryCode': countryCode,
        'supportedCardTypes': supportedCardTypes?.map((e) => e.name).toList(),
      },
    );

    if (result != null) {
      return TappaySdkCommonResult.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappaySdkCommonResult(
        success: false,
        message: 'Encountered an unknown error when init apply pay',
      );
    }
  }

  @override
  Future<TappayPrime> startApplePay({
    bool isAmountPending = false,
    bool isShowTotalAmount = true,
    required List<TappayCartItem> cartItems,
  }) async {
    if (!Platform.isIOS) {
      return TappayPrime(
        success: false,
        message: "Apple pay is only available on iOS",
      );
    }

    if (cartItems.isEmpty) {
      return TappayPrime(success: false, message: 'The cart items cannot be empty');
    }

    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'startApplePay',
      <String, dynamic>{
        'isAmountPending': isAmountPending,
        'isShowTotalAmount': isShowTotalAmount,
        'cartItems': cartItems.map((e) => e.toJson()).toList(),
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when start apply pay',
      );
    }
  }

  @override
  Future<TappaySdkCommonResult> showApplePayResult({required bool result}) async {
    if (!Platform.isIOS) {
      return TappaySdkCommonResult(
        success: false,
        message: "Apple pay is only available on iOS",
      );
    }

    final applePayResult = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'showApplePayResult',
      <String, dynamic>{
        'result': result,
      },
    );

    if (applePayResult != null) {
      return TappaySdkCommonResult.fromJson(Map<String, dynamic>.from(applePayResult));
    } else {
      return TappaySdkCommonResult(
        success: false,
        message: 'Encountered an unknown error when show apply pay result',
      );
    }
  }

  @override
  Future<bool> isLinePayAvailable() async {
    final result = await methodChannel.invokeMethod<bool>(
      'isLinePayAvailable',
    );

    return result ?? false;
  }

  @override
  Future<TappayPrime> getLinePayPrime({required String returnUrl}) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'getLinePayPrime',
      <String, dynamic>{
        'returnUrl': returnUrl,
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when get line pay prime',
      );
    }
  }

  @override
  Future<TappayPrime> redirectLinePay({required String paymentUrl}) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'redirectLinePay',
      <String, dynamic>{
        'paymentUrl': paymentUrl,
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when redirect line pay',
      );
    }
  }

  @override
  Future<bool> isEasyWalletAvailable() async {
    final result = await methodChannel.invokeMethod<bool>(
      'isEasyWalletAvailable',
    );

    return result ?? false;
  }

  @override
  Future<TappayPrime> getEasyWalletPrime({required String returnUrl}) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'getEasyWalletPrime',
      <String, dynamic>{
        'returnUrl': returnUrl,
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when get easy wallet prime',
      );
    }
  }

  @override
  Future<TappayPrime> redirectEasyWallet({required String paymentUrl}) async {
    final result = await methodChannel.invokeMethod<Map<Object?, Object?>>(
      'redirectEasyWallet',
      <String, dynamic>{
        'paymentUrl': paymentUrl,
      },
    );

    if (result != null) {
      return TappayPrime.fromJson(Map<String, dynamic>.from(result));
    } else {
      return TappayPrime(
        success: false,
        message: 'Encountered an unknown error when redirect easy wallet',
      );
    }
  }
}
